local Util     = require("common.Util")
local SkillDefine= require("skill.Define")
local Scan     = require("skill.Scan")
local Unit     = require("skill.Unit")
local Conditions = require("skill.Conditions")
-- *************** 多目标飞行 ***************
local ACTTACK_TYPE_SELF = SkillDefine.ACTTACK_TYPE_SELF
local AOE_TYPE_ROUND  = Scan.AOE_TYPE_ROUND
local calcFlyTime     = Unit.calcFlyTime
local dist          = Util.dist
local getAnglePoint   = Util.getAnglePoint
local getAnglePoint3  = Util.getAnglePoint3
local getDir  = Util.getDir
local random      = math.random
local cos       = math.cos
local sin       = math.sin
local ceil        = math.ceil
local pi        = math.acos(-1)

tempList      = tempList or {}
data = {}

-- (Event)区域范围的多目标 产生作用飞向目标
function onMultiRect(obj, target, node)
    local unit      = Unit.clone(node)
    unit.tid      = target.id
    unit.tuid     = target.uid
    unit.tx       = target.x
    unit.ty       = target.y
    unit.delay      = calcFlyTime(unit) -- 飞行时间
    unit.delayFlyTime = node.delay
    unit:onStart()
end

-- 区域范围的多目标
function multiRect(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local callback    = onMultiRect
    local aoeCenter   = multiArg[1]
    local aoeType   = multiArg[2]
    local maxCount    = multiArg[3]
    local arg1      = multiArg[4]
    local arg2      = multiArg[5]
    if aoeCenter == ACTTACK_TYPE_SELF and aoeType== AOE_TYPE_ROUND then --自身
        node.tx = node.x
        node.ty = node.y
    end

    Scan.handle(aoeType, obj, target, node, callback, conditionFunc, maxCount>0 and maxCount or nil, arg1, arg2)
end


-- (Event)弹射 产生作用飞向目标
function onMultiCharge(obj, target, node)
    local unit      = Unit.clone(node)
    unit.tid      = target.id
    unit.tuid     = target.uid
    unit.tx       = target.x
    unit.ty       = target.y
    unit.delay      = calcFlyTime(unit) -- 飞行时间
    unit.delayFlyTime = data.delay + node.delay
    data.delay      = unit.delay
    unit:onStart()

    node.x = unit.tx
    node.y = unit.ty
end

-- 弹射
function multiCharge(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local callback    = onMultiCharge
    local aoeCenter   = multiArg[1]
    local aoeType   = multiArg[2]
    local maxCount    = multiArg[3]
    local arg1      = multiArg[4]
    local arg2      = multiArg[5]
    data.delay      = 0

    if aoeCenter == ACTTACK_TYPE_SELF then  --自身
        node.tx, node.ty = node.x, node.y
    end

    local aoeCondition    = Scan.aoes[aoeType]
    Scan.data.conditionFunc = conditionFunc
    Scan.data[1]      = arg1
    Scan.data[2]      = arg2
    if target and aoeCondition(obj, target, node) then  -- 锁定目标是否在AOE范围之内
        onMultiCharge(obj, target, node)
        maxCount = maxCount - 1
    end

    Scan.handle(aoeType, obj, target, node, callback, conditionFunc, maxCount , arg1, arg2)
end

-- 扇形多目标
function multiFan(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local angle     = multiArg[1]
    local num     = multiArg[2]
    local offsetAngle = multiArg[3] or 0
    local radius    = multiArg[4]
    local v     = angle/(num-1)
    local radius  = radius or dist(node.x, node.y, node.tx, node.ty)
    local halfAngle = angle/2
    local delay   = node.delay
    for i=0, num-1 do
        local unit      = Unit.clone(node)
        unit.tx, unit.ty   = getAnglePoint(node.dir, node.x, node.y, offsetAngle-halfAngle + v*i, radius)
        unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
        unit.delay      = calcFlyTime(unit) -- 飞行时间
        unit.delayFlyTime = delay
        unit:onStart()
    end
end

-- 圆形随机点
function multiRoundRandom(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local aoeCenter   = multiArg[1]
    local radius    = multiArg[2]
    local num     = multiArg[3]

    local tx, ty
    if aoeCenter == ACTTACK_TYPE_SELF then
        tx, ty = node.x, node.y
    else
        tx, ty = node.tx, node.ty
    end

    local delay = node.delay

    for i=1, num do
        local r     = random() * radius
        local angle   = random() * 360
        local radian  = angle/180 * pi

        local unit    = Unit.clone(node)
        unit.tx, unit.ty = tx + r * cos(radian), ty + r * sin(radian) * 0.6

        if unit.tx<1 then unit.tx = 0 end
        if unit.ty<1 then unit.ty = 0 end
        unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
        unit.delay      = calcFlyTime(unit) -- 飞行时间
        unit.delayFlyTime = delay
        unit:onStart()
    end
end


-- (Event)区域范围中随机目标 产生作用飞向目标
function onMultiRectRandomTarget(obj, target)
    local len   = tempList[0] + 1
    tempList[len] = target
    tempList[0]   = len
end

-- 区域范围中随机目标
function multiRectRandomTarget(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local callback    = onMultiRectRandomTarget
    local aoeCenter   = multiArg[1]
    local aoeType   = multiArg[2]
    local maxCount    = multiArg[3]
    local arg1      = multiArg[4]
    local arg2      = multiArg[5]
    tempList[0]     = 0

    if aoeCenter == ACTTACK_TYPE_SELF then
        node.tx, node.ty = node.x,  node.y
    end

    Scan.handle(aoeType, obj, target, node, callback, conditionFuncNotSelf, maxCount>0 and maxCount or nil, arg1, arg2)

    local objLen = tempList[0]
    if objLen<1 then return end -- 打不到任何人

    local delay = node.delay
    for i=1, maxCount do
        local index = random(1, objLen)
        local target = tempList[index]
        assert(target, index)
        if Conditions.special(obj, target, node) then
            local unit      = Unit.clone(node)
            unit.tid      = target.id
            unit.tuid     = target.uid
            unit.tx       = target.x
            unit.ty       = target.y
            unit.delay      = calcFlyTime(unit) -- 飞行时间
            unit.delayFlyTime = delay
            unit:onStart()
        end
    end
end

-- 圆形区域均匀多目标
function multiRoundTarget(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local aoeCenter   = multiArg[1]
    local radius    = multiArg[2]
    local num     = multiArg[3]
    local offsetAngle = multiArg[4] or 0

    local tx, ty
    if aoeCenter == ACTTACK_TYPE_SELF then
        tx, ty = node.x,  node.y
    else
        tx, ty = node.tx, node.ty
    end

    local delay = node.delay
    for i=1, num do
        local angle     = 360 / num * i
        local radian    = (offsetAngle + angle) / 180 * pi

        local unit      = Unit.clone(node)
        unit.tx, unit.ty   = tx + radius * cos(radian), ty + radius * sin(radian) * 0.6
        if unit.tx<1 then unit.tx = 0 end
        if unit.ty<1 then unit.ty = 0 end
        unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
        unit.delay      = calcFlyTime(unit) -- 飞行时间
        unit.delayFlyTime = delay
        unit:onStart()
    end
end

-- 圆形随机点随机时间 总时间、间隔时间、间隔数量
function multiRoundRandomTime(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local aoeCenter   = multiArg[1]
    local radius    = multiArg[2]
    local totalTime   = multiArg[3]
    local stepTime    = multiArg[4]
    local stepCount   = multiArg[5]

    local tx, ty
    if aoeCenter == ACTTACK_TYPE_SELF then
        tx, ty = node.x,  node.y
    else
        tx, ty = node.tx, node.ty
    end

    local delay = node.delay
    local num = ceil(totalTime/stepTime)
    for i=1, num do
        local delayFlyTime = stepTime*i

        for j=1, stepCount do

            local r       = random()  * radius
            local angle     = random()  * 360
            local radian    = angle/180 * pi
            local unit      = Unit.clone(node)
            unit.tx, unit.ty  = tx + r * cos(radian), ty + r * sin(radian) * 0.6
            if unit.tx<1 then unit.tx = 0 end
            if unit.ty<1 then unit.ty = 0 end
            unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
            unit.delayFlyTime = delayFlyTime + delay
            unit.delay      = calcFlyTime(unit) -- 飞行时间
            unit:onStart()
        end
    end
end

-- 扇形随机点多目标投射
function multiFanRandom(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local angle     = multiArg[1]
    local num     = multiArg[2]
    local offsetAngle = multiArg[3] or 0
    local minRadius   = multiArg[4]
    local maxRadius   = multiArg[5]

    local halfAngle = angle / 2
    local x, y, tx, ty = node.x, node.y, node.tx, node.ty

    local delay = node.delay
    for i = 0, num - 1 do
        local unit      = Unit.clone(node)
        unit.tx, unit.ty   = getAnglePoint3(x, y, tx, ty, offsetAngle - halfAngle + random(0, angle), random(minRadius, maxRadius) )
        unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
        unit.delay      = calcFlyTime(unit) -- 飞行时间
        unit.delayFlyTime = delay
        unit:onStart()
    end
end

-- 扇形自由角度投射
function multiFanAuto(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local angle     = multiArg[1]
    local num     = multiArg[2]
    local offsetAngle = multiArg[3] or 0
    local radius    = multiArg[4] or dist(node.x, node.y, node.tx, node.ty)

    local v     = angle/num
    local halfAngle = angle/2
    local x, y, tx, ty = node.x, node.y, node.tx, node.ty

    local delay = node.delay
    for i = 0, num - 1 do
        local unit      = Unit.clone(node)
        unit.tx, unit.ty   = getAnglePoint3(x, y, tx, ty, offsetAngle - halfAngle + v * i, radius)
        unit.dir = getDir(unit.tx - unit.x, unit.ty - unit.y) -- 修正dir
        unit.delay      = calcFlyTime(unit) -- 飞行时间
        unit.delayFlyTime = delay
        unit:onStart()
    end
end

-- 矩形区域随机初始点直线投射
function multiRectAuto(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg = utilityConfig.multiArg
    local nDist = multiArg[1]
    local nVDist = multiArg[2]
    local nNum = multiArg[3]
    local nTimeSplit = multiArg[4]
    local nRowNum = multiArg[5]
    local delay = node.delay

    local nBeginX, nBeginY = Util.getAnglePoint2(node.x, node.y, node.tx, node.ty, -nDist)
    for i = 1, nNum do
        local unit = Unit.clone(node)
        local nReT = i % nRowNum
        local nCeil = math.ceil(nReT / 2)
        if unit.dir == 2 or unit.dir == 6 then
            unit.x = nBeginX
            unit.y = (i % 2 == 0) and nBeginY + nVDist * nCeil or nBeginY - nVDist * nCeil
            unit.tx = unit.tx
            unit.ty = (i % 2 == 0) and unit.ty + nVDist * nCeil or unit.ty - nVDist * nCeil
        else
            unit.x = (i % 2 == 0) and nBeginX + nVDist * nCeil or nBeginX - nVDist * nCeil
            unit.y = nBeginY
            unit.tx = (i % 2 == 0) and unit.tx + nVDist * nCeil or unit.tx - nVDist * nCeil
            unit.ty = unit.ty
        end
        unit.delay = 0 -- 飞行时间
        unit.delayFlyTime = delay
        if nReT == 0 then
            delay = delay + nTimeSplit
        end
        unit:onStart()
    end
end

-- (Event)区域多目标多根击中
function onMultiRectRepeat(obj, target)
    local len   = tempList[0] + 1
    tempList[len] = target
    tempList[0]   = len
end

-- 区域多目标多根击中（例如扫描到2个目标 但是配置上 射出4根 那么平均2个目标击中2次）
function multiRectRepeat(obj, target, node)
    local utilityConfig = node.utilityConfig
    local multiArg    = utilityConfig.multiArg
    local callback    = onMultiRectRepeat
    local aoeCenter   = multiArg[1]
    local aoeType   = multiArg[2]
    local fireNum   = multiArg[3]
    local arg1      = multiArg[4]
    local arg2      = multiArg[5]
    tempList[0]     = 0

    if aoeCenter == ACTTACK_TYPE_SELF then  --自身
        node.tx, node.ty = node.x, node.y
    end

    Scan.handle(aoeType, obj, target, node, callback, conditionFunc, fireNum, arg1, arg2)
    local objLen = tempList[0]
    if objLen<1 then return end -- 扫描不到任何对象

    local j      = 1
    local iAttenuate = 0  --开始衰减
    while j<= fireNum do
        local has
        local flag   = iAttenuate~=0

        for i=1, objLen do
            local target = tempList[i]
            has = true
            j = j + 1

            local unit      = Unit.clone(node)
            --if flag then unit.delayFlyTime  = iAttenuate * 200 end
            unit.tid      = target.id
            unit.tuid     = target.uid
            unit.tx, unit.ty  = target.x, target.y
            unit.flag     = flag
            unit.delay      = calcFlyTime(unit) -- 飞行时间
            unit.delayFlyTime = iAttenuate * 200
            unit:onStart()

            if  j>fireNum then
                return
            end
        end

        iAttenuate = iAttenuate + 1
        if not has then break end
    end
end


-- 条件判断 不扫描自己
function conditionFunc(obj, target, node)
    return obj~=target and Conditions.special(obj, target, node)
end

function conditionFuncNotSelf(obj, target)
    return obj~=target
end


multiHandles = {
    multiRect,        -- 区域范围的多目标
    multiCharge,      -- 弹射
    multiFan,       -- 扇形投射
    multiRoundRandom,   -- 圆形随机点
    multiRectRandomTarget,  -- 区域范围中随机目标
    multiRoundTarget,   -- 圆形区域均匀多目标
    multiRoundRandomTime, -- 圆形随机点随机时间
    multiFanRandom,     -- 扇形随机点多目标投射
    multiFanAuto,     -- 扇形自由角度投射
    multiRectRepeat,    -- 区域多目标多根击中
    multiRectAuto,
}
